//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
//-----------------------------------------------------------------------------
// Net ICMP.C
//
// This module handles ICMP messages
// Refer to RFC 792, 896, 950, 1122, and 1191
//-----------------------------------------------------------------------------
#include "lh7a400_map.h"
#include "LH7A400_drivers.h"
#include "watertek_drivers.h"
#include "net_net.h"
#include "watertek_main.h"

extern UNS_8 Dm_txBuf[];

//lcd
extern UNS_16 lcdCurX;
extern UNS_16 lcdCurY;
extern UNS_32 BootupState;
extern UNS_32 remote_ipaddr;

//------------------------------------------------------------------------
// This builds a ping response message.  It allocates memory for the
// entire outgoing message, including Eth and IP headers.  See "TCP/IP
// Illustrated, Volume 1" Sect 7.2 for info on Ping messages
//------------------------------------------------------------------------
void ping_send(UNS_8 *inbuf, UNS_32 ipaddr, UNS_16 len)
{
    PING_HEADER  *ping_in;
    PING_HEADER  *ping_out;
    UNS_32 i;

    ping_in = (PING_HEADER  *)(inbuf +  ETH_HEADER_LEN + IP_HEADER_LEN);

    // Ping response message payload starts at offset 34
    ping_out = (PING_HEADER  *)(Dm_txBuf +  ETH_HEADER_LEN + IP_HEADER_LEN);

    ping_out->msg_type = 0;
    ping_out->msg_code = 0;
    ping_out->checksum = 0;
    ping_out->identifier = ping_in->identifier;
    ping_out->sequence = ping_in->sequence;

    memcpy(&ping_out->echo_data, &ping_in->echo_data, len - PING_HEADER_LEN);

    // Compute checksum over the ICMP header plus
    // optional data and insert complement
    ping_out->checksum = ~cksum(Dm_txBuf + ETH_HEADER_LEN + IP_HEADER_LEN, len);

    DBGMSG("ICMP: Response to IP layer !  " );
    ip_send(Dm_txBuf, ipaddr, ICMP_TYPE, len);
}

//------------------------------------------------------------------------
// This builds a ping response message.  It allocates memory for the
// entire outgoing message, including Eth and IP headers.  See "TCP/IP
// Illustrated, Volume 1" Sect 7.2 for info on Ping messages
//------------------------------------------------------------------------
void icmp_send(UNS_8 *inbuf, UNS_32 ipaddr, UNS_8 type, UNS_8 code, UNS_16 len)
{
    PING_HEADER  *ping_in;
    PING_HEADER  *ping_out;
    UNS_32 i;

    ping_in = (PING_HEADER  *)(inbuf +  ETH_HEADER_LEN + IP_HEADER_LEN);

    // Ping response message payload starts at offset 34
    ping_out = (PING_HEADER  *)(Dm_txBuf +  ETH_HEADER_LEN + IP_HEADER_LEN);

    ping_out->msg_type = type;
    ping_out->msg_code = code;
    ping_out->checksum = 0;
    ping_out->identifier = ping_in->identifier;
    ping_out->sequence = ping_in->sequence;

    memcpy(&ping_out->echo_data, &ping_in->echo_data, len - PING_HEADER_LEN);

    // Compute checksum over the ICMP header plus
    // optional data and insert complement
    ping_out->checksum = ~cksum(Dm_txBuf + ETH_HEADER_LEN + IP_HEADER_LEN, len);

    DBGMSG("ICMP: Ping echo to ip !            ");
    ip_send(Dm_txBuf, ipaddr, ICMP_TYPE, len);
}

//------------------------------------------------------------------------
// This handles incoming ICMP messages.  See "TCP/IP Illustrated,
// Volume 1" Sect 6.2 for discussion of the various ICMP messages
//------------------------------------------------------------------------
void icmp_rcve(UNS_8 *inbuf, UNS_16 len)
{
    IP_HEADER *ip;
    UNS_8  msg_type;
    UNS_16 temp;
    UNS_32 i;
    PING_HEADER *ping_packet;

    // Allow for 14 bytes eth header
    ip = (IP_HEADER  *)(inbuf + ETH_HEADER_LEN);

    if (ip->source_ipaddr != remote_ipaddr) return;

    // IP header has been adjusted if necessary to always be
    // 20 bytes so message starts at an offset of 34
    // Validate checksum of entire ICMP message incl data
    if (cksum(inbuf + ETH_HEADER_LEN + IP_HEADER_LEN, len) != 0xFFFF) {
        DBGMSG("ICMP: Error, cksum bad !      " );
        return;
    }
    ping_packet = (PING_HEADER *)(inbuf +  ETH_HEADER_LEN + IP_HEADER_LEN);
    // Switch on the message type
    msg_type = *(inbuf +  ETH_HEADER_LEN + IP_HEADER_LEN);

    switch (msg_type) {
        case 0:
            DBGMSG("ICMP: Ping echo Reply ! ");
            if (BootupState == 0 && ping_packet->sequence == INTSWAP(9999)) {
                BootupState = 1;
            }
            break;

        case 3:
            if (BootupState == 2 && ping_packet->msg_code == 3) {
                BootupState = 1;
                dputs("ICMP: Dest unreachable rcvd ! " );
            }
            break;

        case 8:
            DBGMSG("ICMP: Ping rcvd !             ");
            ping_send(inbuf, ip->source_ipaddr, len);
            break;

        default:
            DBGMSG("ICMP: Error,unknown msg rcvd !" );
            break;
    }
}
